//
// Created on 2024/9/7.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include <iostream>
#include <random>
#include <string>
#include "peer_connection_dependency_factory.h"
#include "modules/audio_device/include/audio_device_data_observer.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
#include "api/video_codecs/builtin_video_decoder_factory.h"
#include "api/video_codecs/builtin_video_encoder_factory.h"
#include "api/create_peerconnection_factory.h"
#include "rtc_log.h"
#include "sdk/ohos/ohos_peer_connection_factory.h"
#include "sdk/ohos/create_ohos_peerconnection_factory.h"

namespace ohosrtc {

std::shared_ptr<PeerConnectionDependencyFactory> PeerConnectionDependencyFactory::Create() {
  auto pcd_factory = std::make_shared<PeerConnectionDependencyFactory>();
  pcd_factory->CreateOHOSPeerConnectionFactory();
  return pcd_factory;
}

void PeerConnectionDependencyFactory::CreateOHOSPeerConnectionFactory() {
  auto ohos_peer_connection_factory = webrtc::CreateOHOSPeerConnectionFactory();
  if (!ohos_peer_connection_factory) {
    return;
  }
  ohos_pc_factory_ = ohos_peer_connection_factory;
}

OHOSPeerConnectionPtr PeerConnectionDependencyFactory::CreateOHOSPeerConnection(RTCConfig config, ohoswebrtc::OHOSPeerConnectionObserver *observer) {
  if (!ohos_pc_factory_) {
    return nullptr;
  }
  auto media_constraints = webrtc::CreateOHOSMediaConstraints({},{{"DtlsSrtpKeyAgreement","true"}});
  auto pc_or_error = ohos_pc_factory_->CreatePeerConnection(config, media_constraints,observer);
  return pc_or_error;
}

// create local stream include video/audio tracks used for publish
OHOSLocalStreamPtr PeerConnectionDependencyFactory::CreateOHOSLocalStream(bool has_audio, bool video_capturer, bool is_screen_cast) {
  RTC_LOG << "create local stream has_audio=" << has_audio << " has_video=" << video_capturer;
  // create media stream
  OHOSLocalStreamPtr ohos_local_stream = CreateOHOSLocalStream(is_screen_cast);
  if (has_audio) { // create audio track
    auto local_audio_track = CreateOHOSLocalAudioTrack();
    ohos_local_stream->MediaStream()->AddAudioTrack(local_audio_track);
    // add audio track to media stream
  }
  if (video_capturer || is_screen_cast) { // create video track when have video capturer
    // create video source
    auto source = CreateOHOSVideoSource(is_screen_cast);
    if (is_screen_cast) {
      screen_source_ = source;
      auto local_video_track = CreateOHOSLocalVideoTrack(screen_source_);
      ohos_local_stream->MediaStream()->AddVideoTrack(local_video_track);
    } else {
      video_source_ = source;
      auto local_video_track = CreateOHOSLocalVideoTrack(video_source_);
      ohos_local_stream->MediaStream()->AddVideoTrack(local_video_track);
    }
  }
  
  ohos_local_stream_ = ohos_local_stream;
  return ohos_local_stream;
}

OHOSLocalStreamPtr PeerConnectionDependencyFactory::CreateOHOSLocalStream(bool is_screen_cast) {
  auto stream_id = "stream-" + GenerateRandomId(8);
  if (is_screen_cast) {
    stream_id += "screen-cast"; 
  }
  rtc::scoped_refptr<ohoswebrtc::OHOSMediaStreamInterface> local_media_stream = ohos_pc_factory_->CreateLocalMediaStream(stream_id);
  rtc::scoped_refptr<OHOSLocalStream> local_stream{new rtc::RefCountedObject<OHOSLocalStream>(local_media_stream)};
  return local_stream;
}

OHOSAudioTrackPtr PeerConnectionDependencyFactory::CreateOHOSLocalAudioTrack() {
  cricket::AudioOptions options;
//  auto media_constraints = webrtc::CreateOHOSMediaConstraints({},{});
  auto media_constraints = webrtc::CreateOHOSMediaConstraints({},{{"DtlsSrtpKeyAgreement","true"}});
  auto audio_source = ohos_pc_factory_->CreateAudioSource(media_constraints);
  auto track_id = "audio-track-" + GenerateRandomId(8);
  auto local_audio_track = ohos_pc_factory_->CreateAudioTrack(audio_source, track_id);
  return local_audio_track;
}

OHOSVideoTrackPtr PeerConnectionDependencyFactory::CreateOHOSLocalVideoTrack(OHOSVideoSourcePtr video_source) {
  auto track_id = "video-track-" + GenerateRandomId(8);
  auto local_video_track = ohos_pc_factory_->CreateVideoTrack(video_source, track_id);
  return local_video_track;
}

OHOSVideoSourcePtr PeerConnectionDependencyFactory::CreateOHOSVideoSource(bool is_screen_cast) {
  auto video_source = ohos_pc_factory_->CreateVideoSource(is_screen_cast);
  return video_source;
}


std::string PeerConnectionDependencyFactory::GenerateRandomId(int length) {
  const char characters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                            "abcdefghijklmnopqrstuvwxyz"
                            "0123456789";

  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> dis(0, sizeof(characters) - 2); // -2是因为最后一个字符是'\0'

  std::string randomString;

  for (size_t i = 0; i < length; ++i) {
    randomString += characters[dis(gen)];
  }

  return randomString;
}
} // namespace ohosrtc